package app.server.project.main.service.service;

import app.server.project.core.constants.Def;
import app.server.project.core.constants.TcpCmd;
import app.server.project.core.websocket.WSMgr;
import app.server.project.main.service.bo.event.LvEvent;
import app.server.project.main.service.bo.event.RechargeSuccessEvent;
import app.server.project.main.service.constants.GlobalCfgKey;
import app.server.project.main.service.db.dao.cfg.GlobalCfgDao;
import app.server.project.main.service.db.dao.user.EnergyInfoDao;
import app.server.project.main.service.db.dao.user.UserInfoDao;
import app.server.project.main.service.db.entity.user.UserEnergyEntity;
import app.server.project.main.service.db.entity.user.UserInfoEntity;
import app.server.project.main.service.dto.EnergyDto;
import app.server.project.main.service.service.recharge.CallbackType;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;

@Slf4j
@Service
public class EnergyService {

    @Autowired
    private GlobalCfgDao globalCfgDao;
    @Autowired
    private EnergyInfoDao energyInfoDao;
    @Autowired
    private UserInfoDao userInfoDao;


    /**
     * 初始化体力值
     *
     * @param userId
     */
    public void chkAndInit(long userId) {
        UserEnergyEntity userEnergyEntity = this.energyInfoDao.getInfoById(userId);
        if (Def.True == userEnergyEntity.getInit()) return;
        long maxNum = this.globalCfgDao.getOneByKey(GlobalCfgKey.Energy_Init_Num).getLong();
        UserInfoEntity userInfoEntity = this.userInfoDao.getUserInfoById(userId);
        userInfoEntity.setEnergy(maxNum);
        userEnergyEntity.setMaxNum(maxNum);
        userEnergyEntity.setFlushTime(System.currentTimeMillis());
        userEnergyEntity.setInit(Def.True);
    }

    /**
     * 等级变化添加体力值上限
     *
     * @param lvEvent
     */
    @EventListener(LvEvent.class)
    public void onLv(LvEvent lvEvent) {
        long lvNum = this.globalCfgDao.getOneByKey(GlobalCfgKey.Energy_Lv_Num).getLong();
        UserEnergyEntity userEnergyEntity = this.energyInfoDao.getInfoById(lvEvent.getUserId());
        this.chkAndInit(lvEvent.getUserId());
        userEnergyEntity.addMaxNum(lvNum * lvEvent.getLvDiff());
        this.sumTimeVal(lvEvent.getUserId());
        this.pushEnergy(lvEvent.getUserId());
    }

    /**
     * 时间自动结算体力值
     *
     * @param userId
     */
    private void sumTimeVal(long userId) {
        int secondRate = 1000;
        var time = this.globalCfgDao.getOneByKey(GlobalCfgKey.Energy_Time_Num).getLong();
        var speed = this.globalCfgDao.getOneByKey(GlobalCfgKey.Energy_Speed_Num).getLong();
        UserEnergyEntity userEnergyEntity = this.energyInfoDao.getInfoById(userId);
        this.chkAndInit(userId);

        var userInfo = this.userInfoDao.getUserInfoById(userId);

        //结算差值
        var second = System.currentTimeMillis() - userEnergyEntity.getFlushTime();
        var flushTime = second / (time * secondRate);
        if (flushTime > Def.Zero) {
            var val = flushTime * speed;
            userInfo.addEnergyNum(val);
            var flushTimeRet = userEnergyEntity.getFlushTime() + flushTime * time * secondRate;
            userEnergyEntity.setFlushTime(flushTimeRet);
        }

        //检查是否超过最大值
        if (userEnergyEntity.getMaxNum() > userInfo.getEnergy()) {
            //开始使用临时体力值
            var temp = userEnergyEntity.getMaxNum() - userInfo.getEnergy();
            if (temp > userEnergyEntity.getRewardNum()) {
                //清空临时体力值
                userInfo.addEnergyNum(userEnergyEntity.getRewardNum());
                userEnergyEntity.setRewardNum(Def.Zero);
            } else {
                //重置最大值
                userInfo.setEnergy(userEnergyEntity.getMaxNum());
                userEnergyEntity.consumeRewardNum(temp);
            }
        } else {
            //重置最大值
            userInfo.setEnergy(userEnergyEntity.getMaxNum());
        }
    }

    /**
     * 消费体力值
     *
     * @param userId
     * @param num
     */
    public boolean consume(long userId, long num, boolean push) {
        this.sumTimeVal(userId);
        UserInfoEntity userInfoEntity = this.userInfoDao.getUserInfoById(userId);
        UserEnergyEntity userEnergyEntity = this.energyInfoDao.getInfoById(userId);
        if ((userInfoEntity.getEnergy() + userEnergyEntity.getRewardNum()) < num) return false;
        if (userInfoEntity.getEnergy() >= num) {
            userInfoEntity.addEnergyNum(-num);
        } else {
            userEnergyEntity.consumeRewardNum((num - userInfoEntity.getEnergy()));
            userInfoEntity.setEnergy(Def.Zero);
        }
        this.sumTimeVal(userId);
        if (push) {
            this.pushEnergy(userId);
        }
        return true;
    }

    /**
     * 添加体力值
     *
     * @param userId
     * @param num
     */
    public void addEnergy(long userId, long num) {
        this.sumTimeVal(userId);
        UserInfoEntity userInfoEntity = this.userInfoDao.getUserInfoById(userId);
        userInfoEntity.addEnergyNum(num);
        //检查最大值
        UserEnergyEntity userEnergyEntity = this.energyInfoDao.getInfoById(userId);
        //检查是否超过最大值
        if (userEnergyEntity.getMaxNum() > userInfoEntity.getEnergy()) {

        } else {
            //重置最大值
            var temp = userInfoEntity.getEnergy() - userEnergyEntity.getMaxNum();
            userEnergyEntity.addRewardNum(temp);
            userInfoEntity.setEnergy(userEnergyEntity.getMaxNum());
        }
        this.pushEnergy(userId);
    }

    /**
     * 添加体力值并改变体力最大值
     *
     * @param userId
     * @param num
     */
    public void addEnergyAndMax(long userId, long num) {
        UserInfoEntity userInfoEntity = this.userInfoDao.getUserInfoById(userId);
        //检查最大值
        UserEnergyEntity userEnergyEntity = this.energyInfoDao.getInfoById(userId);
        this.sumTimeVal(userId);
        userInfoEntity.addEnergyNum(num);
        //开始检查是否溢出
        //检查是否超过最大值
        if (userEnergyEntity.getMaxNum() > userInfoEntity.getEnergy()) {

        } else {
            //重置最大值
            userInfoEntity.setEnergy(userEnergyEntity.getMaxNum());
        }
        this.pushEnergy(userId);
    }

    /**
     * 发送体力
     */
    @EventListener(RechargeSuccessEvent.class)
    public void rewardEnergy(RechargeSuccessEvent event) {
        if (event.getCallbackType() != CallbackType.Energy) return;
        log.info("用户:{}  充值成功开始发放体力:{}", event.getUserId(), event.getParam());
        WSMgr.push(event.getUserId(), TcpCmd.RechargeSuccessTon, event.getParam());
        //发放体力
        this.addEnergy(event.getUserId(), event.getParam());
    }

    /**
     * 构造体力值信息体
     *
     * @param userId
     * @return
     */
    private EnergyDto createDto(long userId) {
        UserEnergyEntity userEnergyEntity = this.energyInfoDao.getInfoById(userId);
        var userInfo = this.userInfoDao.getUserInfoById(userId);
        var time = this.globalCfgDao.getOneByKey(GlobalCfgKey.Energy_Time_Num).getLong();
        var speed = this.globalCfgDao.getOneByKey(GlobalCfgKey.Energy_Speed_Num).getLong();

        return EnergyDto.of(userEnergyEntity, userInfo, time, speed);
    }

    /**
     * 前端读取体力值模块值
     *
     * @param userId
     * @return
     */
    public EnergyDto getDto(long userId) {
        this.sumTimeVal(userId);
        return this.createDto(userId);
    }

    public void pushEnergy(long userId) {
        WSMgr.push(userId, TcpCmd.Energy, this.createDto(userId));
    }
}
